<!DOCTYPE html>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<body>
<script>
  const eventLog = [];

  document.addEventListener('beforeinput', event => {
    const logString =
      `beforeinput: isComposing=${event.isComposing}, data="${event.data}", `
          + `inputType=${event.inputType}`;
    eventLog.push(logString);
  });

  document.addEventListener('textInput', event => {
    const logString = `textInput: data="${event.data}"`;
    eventLog.push(logString);
  });

  document.addEventListener('input', event => {
    const logString =
      `input: isComposing=${event.isComposing}, data="${event.data}", `
          + `inputType=${event.inputType}`;
    eventLog.push(logString);
  });

  document.addEventListener('compositionstart', event => {
    eventLog.push('compositionstart');
  });

  document.addEventListener('compositionupdate', event => {
    const logString = `compositionupdate: data="${event.data}"`;
    eventLog.push(logString);
  });

  document.addEventListener('compositionend', event => {
    const logString = `compositionend: data="${event.data}"`;
    eventLog.push(logString);
  });

  function resetEventLog() {
    eventLog.length = 0;
  }

  function checkTextInputController() {
    assert_not_equals(textInputController, undefined,
                      'This test requires textInputController.');
  }

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.value = 'hello';
    input.focus();
    textInputController.setMarkedTextFromExistingText(0, 5);

    assert_array_equals(eventLog, [
      'compositionstart',
      'compositionupdate: data="hello"',
    ]);
  }, 'setMarkedTextFromExistingText');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.value = 'hello';
    input.select();
    input.focus();

    resetEventLog();
    textInputController.setComposition('');
    assert_array_equals(eventLog, [
      'beforeinput: isComposing=false, data="null", '
          + 'inputType=deleteContentBackward',
      'input: isComposing=false, data="null", inputType=deleteContentBackward',
    ]);
  }, 'setComposition with no composition open, empty text replacing selection');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.focus();

    resetEventLog();
    textInputController.setComposition('');
    assert_array_equals(eventLog, []);
  }, 'setComposition with no composition open, empty text, no selection');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.focus();

    resetEventLog();
    textInputController.setComposition('hello');
    assert_array_equals(eventLog, [
      'compositionstart',
      'beforeinput: isComposing=true, data="hello", '
          + 'inputType=insertCompositionText',
      'compositionupdate: data="hello"',
      'input: isComposing=true, data="hello", inputType=insertCompositionText',
    ]);
  }, 'setComposition with no composition open, non-empty text, no selection');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.focus();
    textInputController.setComposition('hello');
    resetEventLog();

    textInputController.setComposition('');
    assert_array_equals(eventLog, [
      'beforeinput: isComposing=true, data="", inputType=insertCompositionText',
      'compositionupdate: data=""',
      'textInput: data=""',
      'input: isComposing=true, data="null", inputType=insertCompositionText',
      'compositionend: data=""',
    ]);
  }, 'setComposition with open composition, empty text');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.focus();
    textInputController.setComposition('hello');
    resetEventLog();

    textInputController.setComposition('hello world');
    assert_array_equals(eventLog, [
      'beforeinput: isComposing=true, data="hello world", '
          + 'inputType=insertCompositionText',
      'compositionupdate: data="hello world"',
      'input: isComposing=true, data="hello world", '
          + 'inputType=insertCompositionText',
    ]);
  }, 'setComposition with open composition, non-empty text');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.focus();
    textInputController.setComposition('hello');
    resetEventLog();

    textInputController.insertText('hello world');
    assert_array_equals(eventLog, [
      'beforeinput: isComposing=true, data="hello world", '
          + 'inputType=insertCompositionText',
      'compositionupdate: data="hello world"',
      'textInput: data="hello world"',
      'input: isComposing=true, data="hello world", '
          + 'inputType=insertCompositionText',
      'compositionend: data="hello world"',
    ]);
  }, 'insertText with open composition, non-empty text');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.focus();
    textInputController.setComposition('hello');
    resetEventLog();

    textInputController.insertText('');
    assert_array_equals(eventLog, [
      'beforeinput: isComposing=true, data="", inputType=insertCompositionText',
      'compositionupdate: data=""',
      'textInput: data=""',
      'input: isComposing=true, data="null", inputType=insertCompositionText',
      'compositionend: data=""',
    ]);
  }, 'insertText with open composition, empty text');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.focus();
    resetEventLog();

    textInputController.insertText('hello');
    assert_array_equals(eventLog, [
      'beforeinput: isComposing=false, data="hello", inputType=insertText',
      'textInput: data="hello"',
      'input: isComposing=false, data="hello", inputType=insertText',
    ]);
  }, 'insertText without open composition, non-empty text');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.focus();
    resetEventLog();

    textInputController.insertText('');
    assert_array_equals(eventLog, []);
  }, 'insertText without open composition, empty text');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.focus();
    textInputController.setComposition('hello');
    resetEventLog();

    textInputController.unmarkText();
    assert_array_equals(eventLog, [
      'compositionend: data="hello"',
    ]);
  }, 'unmarkText, not too long for input');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.setAttribute('maxlength', 1);
    input.focus();
    textInputController.setComposition('hello');
    resetEventLog();

    textInputController.unmarkText();
    assert_array_equals(eventLog, [
      'beforeinput: isComposing=true, data="hello", '
          + 'inputType=insertCompositionText',
      'compositionupdate: data="hello"',
      'textInput: data="h"',
      'input: isComposing=true, data="h", inputType=insertCompositionText',
      'compositionend: data="hello"',
    ]);
  }, 'unmarkText, too long for input');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.focus();
    textInputController.setComposition('hello');
    resetEventLog();

    textInputController.unmarkAndUnselectText();
    assert_array_equals(eventLog, [
      'compositionend: data="hello"',
    ]);
  }, 'unmarkAndUnselectText, not too long for input');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.setAttribute('maxlength', 1);
    input.focus();
    textInputController.setComposition('hello');
    resetEventLog();

    textInputController.unmarkAndUnselectText();
    assert_array_equals(eventLog, [
      'beforeinput: isComposing=true, data="hello", '
          + 'inputType=insertCompositionText',
      'compositionupdate: data="hello"',
      'textInput: data="h"',
      'input: isComposing=true, data="h", inputType=insertCompositionText',
      'compositionend: data="hello"',
    ]);
  }, 'unmarkAndUnselectText, too long for input');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.value = 'hello';
    input.focus();
    input.setSelectionRange(2, 2);
    resetEventLog();

    textInputController.extendSelectionAndDelete(1, 1);
    assert_array_equals(eventLog, [
      'beforeinput: isComposing=false, data="null", '
          + 'inputType=deleteContentBackward',
      'input: isComposing=false, data="null", inputType=deleteContentBackward',
    ]);
  }, 'extendSelectionAndDelete, no composition open');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.value = 'hello';
    input.focus();
    textInputController.setMarkedTextFromExistingText(0, 5);
    input.setSelectionRange(2, 2);
    resetEventLog();

    textInputController.extendSelectionAndDelete(1, 1);
    assert_array_equals(eventLog, [
      'beforeinput: isComposing=false, data="null", '
          + 'inputType=deleteContentBackward',
      'input: isComposing=false, data="null", inputType=deleteContentBackward',
    ]);
  }, 'extendSelectionAndDelete, composition open');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.value = 'hello';
    input.focus();
    input.setSelectionRange(2, 2);
    resetEventLog();

    textInputController.deleteSurroundingText(1, 1);
    assert_array_equals(eventLog, [
      'beforeinput: isComposing=false, data="null", '
          + 'inputType=deleteContentBackward',
      'input: isComposing=false, data="null", inputType=deleteContentBackward',
      'beforeinput: isComposing=false, data="null", '
          + 'inputType=deleteContentBackward',
      'input: isComposing=false, data="null", inputType=deleteContentBackward',
    ]);
  }, 'deleteSurroundingText, no composition open');

  test(() => {
    checkTextInputController();

    const input = document.createElement('input');
    document.body.appendChild(input);

    input.value = 'hello';
    input.focus();
    textInputController.setMarkedTextFromExistingText(0, 5);
    input.setSelectionRange(2, 2);
    resetEventLog();

    textInputController.deleteSurroundingText(1, 1);
    assert_array_equals(eventLog, [
      'beforeinput: isComposing=false, data="null", '
           + 'inputType=deleteContentBackward',
      'input: isComposing=false, data="null", inputType=deleteContentBackward',
      'beforeinput: isComposing=false, data="null", '
         + 'inputType=deleteContentBackward',
      'input: isComposing=false, data="null", inputType=deleteContentBackward',
    ]);
  }, 'deleteSurroundingText, composition open');
</script>
